package service_sys

import (
	"context"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/internal/req/req_sys"
	"go_web/internal/res/res_sys"
	"go_web/pkg/req"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"math"

	"github.com/fatih/structs"
	"github.com/jinzhu/copier"
	"gorm.io/gen"
	"gorm.io/gen/field"
)

type SysRouteAuthService struct{}

// 创建新的 SysRouteAuthService
func NewSysRouteAuthService() *SysRouteAuthService {
	return &SysRouteAuthService{}
}

// 分页查询
func (*SysRouteAuthService) Page(c context.Context, pageReq req_sys.SysRouteAuthPageReq) (*res.PageRes, error) {
	offset := (pageReq.Page - 1) * pageReq.PageSize
	q := repo_sys.SysRouteAuth.WithContext(c)

	// 排序处理
	if pageReq.SortField != nil {
		sortField := utils.ConvertToSnakeCase(*pageReq.SortField)
		orderFieldExpr := field.NewUnsafeFieldRaw(sortField)
		if pageReq.SortOrder != nil {
			if *pageReq.SortOrder == "asc" {
				q = q.Order(orderFieldExpr.Asc())
			} else {
				q = q.Order(orderFieldExpr.Desc())
			}
		} else {
			q = q.Order(orderFieldExpr.Asc())
		}
	}

	// 执行分页查询
	list, count, err := q.FindByPage(offset, pageReq.PageSize)
	if err != nil {
		return nil, err
	}

	// 计算总页数
	page := res.PageRes{
		List:     list,
		Total:    count,
		Page:     pageReq.Page,
		PageSize: pageReq.PageSize,
		Pages:    int64(math.Ceil(float64(count) / float64(pageReq.PageSize))),
	}

	return &page, nil
}

// 添加 SysRouteAuth 已开启事务
func (*SysRouteAuthService) Add(c context.Context, addReq req_sys.SysRouteAuthAddReq) (int64, error) {
	var SysRouteAuth model_sys.SysRouteAuth
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysRouteAuth.WithContext(c)
		err := copier.Copy(&SysRouteAuth, &addReq)
		if err != nil {
			return err
		}
		err = q.Create(&SysRouteAuth)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return SysRouteAuth.ID, nil
}

// 编辑 SysRouteAuth 已开启事务
func (*SysRouteAuthService) Edit(c context.Context, editReq req_sys.SysRouteAuthEditReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysRouteAuth.WithContext(c).Where(repo_sys.SysRouteAuth.ID.Eq(editReq.ID))
		SysRouteAuth, err := q.First()
		if err != nil {
			return err
		}
		err = copier.Copy(&SysRouteAuth, &editReq)
		if err != nil {
			return err
		}
		result, err = q.Updates(structs.Map(SysRouteAuth))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		if utils.IsOptimisticLockError(err) {
			return -1, nil // 乐观锁报错（版本不一致）
		}
		return 0, err
	}
	return result.RowsAffected, nil
}

// 删除 SysRouteAuth 已开启事务
func (*SysRouteAuthService) Delete(c context.Context, idsReq req.IdsReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := repo_sys.SysRouteAuth.WithContext(c)
		ids, err := idsReq.ToInt64Slice()
		if err != nil {
			return err
		}
		sysUserList, err := q.Where(repo_sys.SysUser.ID.In(ids...)).Find()
		if err != nil {
			return err
		}
		result, err = q.Delete(sysUserList...)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return result.RowsAffected, nil
}

// 查看 SysRouteAuth 详情
func (*SysRouteAuthService) Detail(c context.Context, userId int64) (*model_sys.SysRouteAuth, error) {
	q := repo_sys.SysRouteAuth.WithContext(c)
	SysRouteAuth, err := q.Where(repo_sys.SysRouteAuth.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	return SysRouteAuth, nil
}

func processRouteNodeRole(node *res_sys.SysRouteAllRes, role string, result []*model_sys.SysRouteAuth) {
	if node.Status {
		var sysRouteAuth *model_sys.SysRouteAuth = &model_sys.SysRouteAuth{
			Role:       role,
			RouteId:    node.ID,
			TargetType: "ROLE",
			IsAccess:   node.IsAuth,
		}
		result = append(result, sysRouteAuth)
	}
}

func processButtonNodesRole(parentNode *res_sys.SysRouteAllRes, role string, result []*model_sys.SysRouteAuth) {
	for _, node := range parentNode.ButtonAuthList {
		if node.Status {
			var sysRouteAuth *model_sys.SysRouteAuth = &model_sys.SysRouteAuth{
				RouteId:    node.ID,
				Role:       role,
				TargetType: "ROLE",
				IsAccess:   node.IsAuth,
			}
			result = append(result, sysRouteAuth)
		}
	}
}

func getRoleFlatRouteAuth(sysRouteAllParamList []*res_sys.SysRouteAllRes, role string) []*model_sys.SysRouteAuth {
	sysRouteAuthList := make([]*model_sys.SysRouteAuth, 0)
	for _, sysRouteAll := range sysRouteAllParamList {
		processRouteNodeRole(sysRouteAll, role, sysRouteAuthList)
		if sysRouteAll.Children != nil {
			sysRouteAuthList = append(sysRouteAuthList, getRoleFlatRouteAuth(sysRouteAll.Children, role)...)
		}
		if sysRouteAll.ButtonAuthList != nil {
			processButtonNodesRole(sysRouteAll, role, sysRouteAuthList)
		}
	}
	return sysRouteAuthList
}

// 保存角色的路由权限
func (*SysRouteAuthService) SaveRoleSysRouteAuth(c context.Context,
	sysRouteAllParamList []*res_sys.SysRouteAllRes, role string) error {
	_, err := repo_sys.SysRouteAuth.Where(repo_sys.SysRouteAuth.Role.Eq(role)).Delete()
	if err != nil {
		return err
	}
	roleFlatRouteAuth := getRoleFlatRouteAuth(sysRouteAllParamList, role)
	return repo_sys.SysRouteAuth.Save(roleFlatRouteAuth...)
}

func processRouteNodeUser(node *res_sys.SysRouteAllRes, userID int64, result []*model_sys.SysRouteAuth) {
	if node.Status {
		var sysRouteAuth *model_sys.SysRouteAuth = &model_sys.SysRouteAuth{
			TargetId:   userID,
			RouteId:    node.ID,
			TargetType: "USER",
			IsAccess:   node.IsAuth,
		}
		result = append(result, sysRouteAuth)
	}
}

func processButtonNodesUser(parentNode *res_sys.SysRouteAllRes, userID int64, result []*model_sys.SysRouteAuth) {
	for _, node := range parentNode.ButtonAuthList {
		if node.Status {
			var sysRouteAuth *model_sys.SysRouteAuth = &model_sys.SysRouteAuth{
				RouteId:    node.ID,
				TargetId:   userID,
				TargetType: "ROLE",
				IsAccess:   node.IsAuth,
			}
			result = append(result, sysRouteAuth)
		}
	}
}

func getUserFlatRouteAuth(sysRouteAllParamList []*res_sys.SysRouteAllRes, userID int64) []*model_sys.SysRouteAuth {
	sysRouteAuthList := make([]*model_sys.SysRouteAuth, 0)
	for _, sysRouteAll := range sysRouteAllParamList {
		processRouteNodeUser(sysRouteAll, userID, sysRouteAuthList)
		if sysRouteAll.Children != nil {
			sysRouteAuthList = append(sysRouteAuthList, getUserFlatRouteAuth(sysRouteAll.Children, userID)...)
		}
		if sysRouteAll.ButtonAuthList != nil {
			processButtonNodesUser(sysRouteAll, userID, sysRouteAuthList)
		}
	}
	return sysRouteAuthList
}

// 保存用户的路由权限
func (*SysRouteAuthService) SaveUserSysRouteAuth(c context.Context,
	sysRouteAllParamList []*res_sys.SysRouteAllRes, userID int64) error {
	_, err := repo_sys.SysRouteAuth.Where(repo_sys.SysRouteAuth.TargetID.Eq(userID)).Delete()
	if err != nil {
		return err
	}
	roleFlatRouteAuth := getUserFlatRouteAuth(sysRouteAllParamList, userID)
	return repo_sys.SysRouteAuth.Save(roleFlatRouteAuth...)
}
